package com.dhcc.core.modules.system.controller;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpSession;

import com.dhcc.license.core.CustomLicenseManager;
import com.dhcc.license.core.LicenseVerify;
import com.dhcc.license.interceptor.VteLicense;
import com.dhcc.license.listener.LicenseCheckListener;
import de.schlichtherle.license.LicenseManager;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.UnavailableSecurityManagerException;
import org.apache.shiro.session.Session;
import org.pac4j.core.context.Pac4jConstants;
import org.pac4j.core.profile.CommonProfile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.dhcc.core.config.properties.SsoProperties;
import com.dhcc.core.framework.base.controller.BaseController;
import com.dhcc.core.framework.exception.BizException;
import com.dhcc.core.framework.result.R;
import com.dhcc.core.framework.result.node.ZTreeNodeMenu;
import com.dhcc.core.framework.security.ShiroKit;
import com.dhcc.core.framework.util.CommonUtil;
import com.dhcc.core.framework.util.HttpContextUtil;
import com.dhcc.core.framework.util.JsonUtil;
import com.dhcc.core.modules.system.cache.config.ConfigCache;
import com.dhcc.core.modules.system.cache.resource.ResourceCache;
import com.dhcc.core.modules.system.cache.scan.ScanCache;
import com.dhcc.core.modules.system.cache.user.UserCache;
import com.dhcc.core.modules.system.entity.User;
import com.dhcc.core.modules.system.service.IResourceService;
import com.dhcc.core.modules.system.service.IUserService;
import com.dhcc.core.modules.system.vo.ScanLoginVo;
import com.google.code.kaptcha.Constants;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.RandomUtil;
import io.buji.pac4j.token.Pac4jToken;

/**
 * 后台登录控制器
 *
 * @ClassName: LoginController
 * @Description: 描述
 * @author: cyf
 * @date: 2018年1月2日 上午10:19:32
 */
@Controller("backendLoginController")
@RequestMapping("${sys.backendPath}")
public class LoginController extends BaseController {

    @Autowired
    IResourceService resourceService;

    @Autowired
    IUserService userService;

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Autowired
    private LicenseCheckListener listener;

    @Value("${sys.backendPath}")
    private String backendPath;

    @Value("${sys.sysFullName}")
    private String sysFullName;

    @Value("${sys.orgFullName}")
    private String orgFullName;

    @Value("${sys.resetPassOpen}")
    private String resetPassOpen; //是否开启忘记密码的功能 默认不开启

    @Value("${sys.resetPassVcodeTimeout}")
    private int resetPassVcodeTimeout; //短信验证码的失效时间

    @Value("${sys.wxLoginOpen}")
    private String wxLoginOpen; //是否开启微信登录的功能 默认不开启

    @Value("${sys.scanLoginOpen}")
    private String scanLoginOpen; //是否开启扫码登录的功能 默认不开启

    private String PREFIX = "/backend/";

    /**
     * 跳转到主页
     */
//    @VteLicense
    @RequestMapping(method = RequestMethod.GET)
    public String index(Model model) {
        // 获取菜单列表
        User user = UserCache.me().getUserById(this.getLoginUser().getId());
        List<ZTreeNodeMenu> ls = ResourceCache.me().getUserMenus(user.getId(), user.getDeptIds(), user.getRoleIds());
        if (ls == null || ls.size() == 0) {
            ShiroKit.getSubject().logout();
            model.addAttribute("tips", "该用户没有任何权限，无法登陆");
            model.addAttribute("orgFullName", orgFullName);
            model.addAttribute("sysFullName", sysFullName);
            // 如果启用了单点登录，则屏蔽记住密码的功能
            if (SsoProperties.me().hasForm()) {
                model.addAttribute("isShow", true);
            } else {
                model.addAttribute("isShow", false);
            }
            //如果启用了密码重置，则显示密码重置的链接
            if(CommonUtil.equals(resetPassOpen,"false")){
                model.addAttribute("showResetPass", false);
            }else{
                model.addAttribute("showResetPass", true);
            }

            //如果启用了微信登录，则显示微信登录的入口
            if (CommonUtil.equals(wxLoginOpen, "false")) {
                model.addAttribute("wxLoginOpen", false);
            } else {
                model.addAttribute("wxLoginOpen", true);
            }

            //如果启用了扫码登录，则显示扫码登录的入口
            if (CommonUtil.equals(scanLoginOpen, "false")) {
                model.addAttribute("scanLoginOpen", false);
            } else {
                model.addAttribute("scanLoginOpen", true);
            }

            return PREFIX + "login.html";
        }
        List<ZTreeNodeMenu> menus = ZTreeNodeMenu.buildMenu(ls);
        model.addAttribute("menus", JsonUtil.toJson(menus));// 所有目录
        // 获取用户头像
        model.addAttribute("avatar", user.getAvatar());
        model.addAttribute("sysFullName", sysFullName);
        model.addAttribute("orgFullName", orgFullName);

        // 如果启用了单点登录，则屏蔽注销和修改密码的功能
        if (SsoProperties.me().hasForm()) {
            model.addAttribute("isShow", true);
        } else {
            model.addAttribute("isShow", false);
        }
        boolean isRole = ShiroKit.hasAnyRoles("director,administrator,yiwubu");
        String homeUrl = "analysis/qcportal";
        if(isRole) {
            homeUrl = "analysis/qcportal";
        }else {
            homeUrl = "analysis/qcportal";//暂时不用
        }
        model.addAttribute("homeUrl", homeUrl);
        return PREFIX + "index.html";
    }

    /**
     * 跳转到登录页面
     */
    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String login(Model model) {
        //获取证书有效日期
        /*LicenseVerify licenseVerify = new LicenseVerify();
        Map<String, Object> map = licenseVerify.getLicenseExpireDate(listener.getVerifyParam());
        if (map.size()==0) {
            model.addAttribute("tips", "证书无效或已过期，请联系管理员！");
        } else {
            Date expiryTime = (Date) map.get("expiryTime");
            long days = DateUtil.between(DateUtil.date(), expiryTime, DateUnit.DAY);
            if (days <= 30) {
                model.addAttribute("tips", MessageFormat.format("证书还有{0}天到期，请及时申请！", days));
            } else {
                model.addAttribute("tips", "");
            }
        }*/
        model.addAttribute("tips", "");
        model.addAttribute("orgFullName", orgFullName);
        model.addAttribute("sysFullName", sysFullName);
        // 如果启用了单点登录，则屏蔽记住密码的功能
        if (SsoProperties.me().hasForm()) {
            model.addAttribute("isShow", true);
        } else {
            model.addAttribute("isShow", false);
        }
        //如果启用了密码重置，则显示密码重置的链接
        if(CommonUtil.equals(resetPassOpen,"false")){
            model.addAttribute("showResetPass", false);
        }else{
            model.addAttribute("showResetPass", true);
        }

        //如果启用了微信登录，则显示微信登录的入口
        if (CommonUtil.equals(wxLoginOpen, "false")) {
            model.addAttribute("wxLoginOpen", false);
        } else {
            model.addAttribute("wxLoginOpen", true);
        }

        //如果启用了扫码登录，则显示扫码登录的入口
        if (CommonUtil.equals(scanLoginOpen, "false")) {
            model.addAttribute("scanLoginOpen", false);
        } else {
            model.addAttribute("scanLoginOpen", true);
        }

        User user = ShiroKit.getUser();
        if (ShiroKit.isAuthenticated() || user != null) {
            // 如果是记住密码就把 user profile 放到session里，不然pac4j不认
            Session session = SecurityUtils.getSubject().getSession(true);
            if (session != null) {
                try {
                    final LinkedHashMap<String, CommonProfile> profiles = new LinkedHashMap<>();
                    final CommonProfile profile = new CommonProfile();
                    profile.setId(user.getLoginName());
                    profile.setRemembered(true);
                    profile.addAttribute(Pac4jConstants.USERNAME, user.getLoginName());
                    profiles.put("form", profile);
                    session.setAttribute(Pac4jConstants.USER_PROFILES, profiles);
                } catch (final UnavailableSecurityManagerException e) {
                    logger.warn("Should happen just once at startup in some specific case of Shiro Spring configuration", e);
                }
            }
            return REDIRECT + backendPath + "/";
        } else {
            return PREFIX + "login.html";
        }
    }

    /**
     * 跳转到密码找回页面
     */
    @RequestMapping(value = "/passwordReset", method = RequestMethod.GET)
    public String passwordReset(Model model) {
        return PREFIX + "resetPass.html";
    }

    /**
     * 获取手机验证码
     * @param userCode
     * @return
     */
    @RequestMapping(value = "/getVcode", method = RequestMethod.POST)
    @ResponseBody
    public Object getVcode(@RequestParam String userCode,@RequestParam String kaptcha){
        String code = (String) super.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY);
        if (CommonUtil.isEmpty(kaptcha) || !kaptcha.equals(code)) {
            throw new BizException("验证码错误，请重新检查！");
        }
        if(CommonUtil.isEmpty(userCode)){
            throw new BizException("不存在的账户名称，请确认是否填写了账户名称！");
        }
        User user = UserCache.me().getUserByCode(userCode);
        if(CommonUtil.isNotEmpty(user)){
            if(CommonUtil.isNotEmpty(user.getPhone())){
                //如果电话不为空，则调用短信平台来生成vcode
                String vcode = RandomUtil.randomNumbers(6);
                //调用短信API，发送短信内容
                HttpSession session=HttpContextUtil.getRequest().getSession();
                session.setAttribute("checkCode",vcode);
                session.setAttribute("sendCodeTimeStamp",System.currentTimeMillis()); //记录时间戳 以便比对
            }else{
                throw new BizException("该账户未绑定手机号，请使用微信找回或登录！");
            }
        }else{
            throw new BizException("不存在该账户，请检查账户名称！");
        }
        return R.ok();
    }

    @RequestMapping(value = "/verifyCode", method = RequestMethod.POST)
    @ResponseBody
    public Object verifyCode(@RequestParam String vcode){
        if(CommonUtil.isEmpty(vcode)){
            throw new BizException("验证码为空！");
        }
        HttpSession session=HttpContextUtil.getRequest().getSession();
        String xcode = session.getAttribute("checkCode").toString();
        String sendCodeTimeStamp = session.getAttribute("sendCodeTimeStamp").toString();
        if(CommonUtil.isNotEmpty(xcode)&&CommonUtil.isNotEmpty(sendCodeTimeStamp)){
            Long createTime = Long.parseLong(sendCodeTimeStamp);
            Date startDate = DateUtil.date(createTime);
            long count=DateUtil.between(startDate,DateUtil.date(), DateUnit.MINUTE);
            if(count>resetPassVcodeTimeout){
                //超过五分钟
                session.removeAttribute("checkCode");
                session.removeAttribute("sendCodeTimeStamp");
                return R.error("无效的验证码,验证码已过期！");
            }else{
                if(CommonUtil.notEquals(vcode,xcode)){
                    return R.error("验证码错误！");
                }
            }
        }else{
            throw new BizException("无效的验证码,验证码已过期！");
        }
        return R.ok();
    }


    /**
     * 重置密码为新密码
     * @param userCode
     * @return
     */
    @RequestMapping(value = "/resetPass", method = RequestMethod.POST)
    @ResponseBody
    public Object resetPass(@RequestParam String userCode,@RequestParam String newPass,@RequestParam String confirmPass,@RequestParam String vcode){
        if(CommonUtil.isEmpty(userCode)){
            throw new BizException("不存在的账户名称，请确认是否填写了账户名称！");
        }
        if(CommonUtil.isEmpty(newPass)||CommonUtil.isEmpty(confirmPass)||CommonUtil.notEquals(newPass,confirmPass)){
            throw new BizException("两次密码不一致或密码为空！");
        }
        User user = UserCache.me().getUserByCode(userCode);
        if(CommonUtil.isNotEmpty(user)){
            //验证通过的话，则进行密码修改操作
            String newMd5 = ShiroKit.md5(confirmPass, user.getSalt());
            user.setPassword(newMd5);
            user.updateById();
        }else{
            throw new BizException("不存在该账户，请检查账户名称！");
        }
        return R.ok();
    }

    /**
     * 微信登录
     * @param model
     * @return
     */
    @RequestMapping(value = "/wechatLogin", method = RequestMethod.GET)
    public String wechatLogin(Model model) {
        String wxUrl = ConfigCache.me().getValueByKey("wx.loginUrl","https://open.weixin.qq.com/connect/qrconnect");
        //当前oa系统在微信开放平台上的appid标识
        String wxAppId = ConfigCache.me().getValueByKey("wx.appid","oa");
        String redirect_uri = ConfigCache.me().getValueByKey("wx.redirect_uri","http://www.baidu.com");
        String url =wxUrl+"?appid="+wxAppId+"&redirect_uri="+redirect_uri+"&response_type=code&scope=snsapi_login";
        model.addAttribute("wxloginUrl",url);
        return PREFIX + "wechatLogin.html";
    }

    /**
     * 手机扫码登录
     * @return
     */
    @RequestMapping(value = "/scanLogin", method = RequestMethod.POST)
    @ResponseBody
    public String scanLogin() {
        String simpleUUID = UUID.randomUUID().toString();
        ScanCache.me().getUserIdByUuid(simpleUUID);
        String url = "/pages/apps/scanLogin?uuid="+simpleUUID;
        return url;
    }

    /**
     * 根据uuid判断当前用户有没有在手机上确认登录
     * @return
     */
    @RequestMapping(value = "/isLogin", method = RequestMethod.POST)
    @ResponseBody
    public R isLogin(@RequestParam String uuid) {
        Map<String, Object> map = new HashMap<>();
        map.put("isScan", "");
        ScanLoginVo scanLoginVo = ScanCache.me().getUserIdByUuid(uuid);
        String userId = scanLoginVo.getUserId();
        Boolean isScanLogin = scanLoginVo.getIsScanLogin();
        if(CommonUtil.isNotEmpty(userId)) {
            User user = UserCache.me().getUserById(Long.parseLong(userId));
            if(!isScanLogin) {
                // 获取用户头像
                map.put("avatar", user.getAvatar());
                map.put("userName", user.getName());
                map.put("isScan", "scan");//只扫码未确认登录
                return R.ok().data(map);
            }
            User loginUser = ShiroKit.getUser();
            if (CommonUtil.isEmpty(loginUser) || CommonUtil.notEquals(user, loginUser)){
                CommonProfile profile = new CommonProfile();
                profile.setId(user.getLoginName());
                profile.addAttribute(Pac4jConstants.USERNAME, user.getLoginName());
                List<CommonProfile> profileList = new ArrayList<>();
                profileList.add(profile);
                Pac4jToken pac4jToken = new Pac4jToken(profileList, true);
                SecurityUtils.getSecurityManager().login(SecurityUtils.getSubject(), pac4jToken);
            }
            map.put("isScan", "login");//确认登录
        }
        return R.ok().data(map);
    }
}
